package algorithmlearn.sort;

/*
二分查找  对没有重复数据的有序的数据集合
针对的是一个有序的数据集合，查找思想有点类似分治思想。每次都通过跟区间的中间元素对比，将待查找的区间缩小为之前的一半，直到找到要查找的元素，或者区间被缩小为 0
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] array = {1, 2, 4, 5, 6, 7, 8, 9, 10, 16, 17,  19, 20, 23};
        System.out.println(binarySearch1(array, 4));
        System.out.println(binarySearch2(array, 0, array.length - 1, 4));
    }
    //二分查找的递归与非递归实现

    //二分查找的非递归实现

    /**
     * 着重强调一下容易出错的 3 个地方。
     * 1. 循环退出条件
     * 注意是 low<=high，而不是 low<high。
     * 2.mid 的取值
     * 实际上，mid=(low+high)/2 这种写法是有问题的。因为如果 low 和 high 比较大的话，
     * 两者之和就有可能会溢出。改进的方法是将 mid 的计算方式写成 low+(high-low)/2。
     * 更进一步，如果要将性能优化到极致的话，
     * 我们可以将这里的除以 2 操作转化成位运算 low+((high-low)>>1)。因为相比除法运算来说，计算机处理位运算要快得多。
     * 个人觉得二分查找进行优化时，还个细节注意：
     * 将mid = lo + (hi - lo) /2，将除法优化成移位运算时，得注意运算符的优先级，千万不能写成这样：mid = lo + (hi - lo) >> 1
     * 3.low 和 high 的更新
     * low=mid+1，high=mid-1。注意这里的 +1 和 -1，如果直接写成 low=mid 或者 high=mid，
     * 就可能会发生死循环。比如，当 high=3，low=3 时，如果 a[3] 不等于 value，就会导致一直循环不退出。
     */
    public static int binarySearch1(int[] array, int value) {
        if (array == null) {
            return -1;
        }
        int low = 0;
        int high = array.length - 1;

        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (array[mid] == value) {
                return mid;
            } else if (array[mid] > value) {
                high = mid - 1;
            } else if (array[mid] < value) {
                low = mid + 1;
            }
        }
        return -1;
    }

    //二分查找的递归实现

    /**
     * @param array 查找的数组
     * @param low   区间low的下标
     * @param high  区间high的下标
     * @param value 要查找的值
     * @return
     */
    public static int binarySearch2(int[] array, int low, int high, int value) {
        if (low > high) return -1;
        int mid = low + (high - low) / 2;
        if (array[mid] == value) {
            return mid;
        } else if (array[mid] > value) {
            high = mid - 1;
            return binarySearch2(array, low, high, value);
        } else {
            low = mid + 1;
            return binarySearch2(array, low, high, value);
        }
    }
}
